#include "stdafx.h"
#include "Txn.h"
#include "HeapMgr.h"

Txn::Txn(int iTxnId)
:m_iTxnId(iTxnId),
m_bStarted(FALSE)
{
}

Txn::~Txn(void)
{
	// Delete all backup memory
	std::map<void*, void*>::const_iterator itEnd = m_mMemBackup.end();
	std::map<void*, void*>::const_iterator it;
	for(it = m_mMemBackup.begin(); it != itEnd; ++it)
		delete [] it->second;

	m_mMemBackup.clear();
}

// Get the TxnId
int Txn::GetId() const
{
	return m_iTxnId;
}

// Start the transaction
BOOL Txn::Start()
{
	m_bStarted = TRUE;
	return HeapMgr::Get()->LockAll();

}

// End (commit) the transaction
// Lock all relative memory
BOOL Txn::End()
{
	m_bStarted = FALSE;

	// Save the backup delta
	// Get memory manager
	HeapMgr* pHeapMgr = HeapMgr::Get();

	// Get page size
	size_t nPageSize = pHeapMgr->GetPageSize();

	// Restore each page
	if(m_mMemBackup.size() > 0)
	{
		std::map<void*, void*>::iterator it;
		for(it = m_mMemBackup.begin(); it != m_mMemBackup.end(); it++)
		{
			TXN_ASSERT(it->second);

			DWORD* original = (DWORD*)it->first;
			DWORD* backup = (DWORD*)it->second;
			DWORD* delta = (DWORD*)it->second;

			for (size_t i = 0; i < nPageSize / sizeof(DWORD); ++i)
			{
				delta[i] = original[i] ^ backup[i];
			}
		}
	}


	return HeapMgr::Get()->UnlockAll();
}

// Abort the transaction
BOOL Txn::Abort()
{
	return TRUE;
}

// Undo the transaction
BOOL Txn::Undo()
{
	if(m_bStarted)
		return FALSE;

	// Get memory manager
	HeapMgr* pHeapMgr = HeapMgr::Get();

	// Get page size
	size_t nPageSize = pHeapMgr->GetPageSize();

	// Restore each page
	if(m_mMemBackup.size() > 0)
	{
		std::map<void*, void*>::iterator it;
		for(it = m_mMemBackup.begin(); it != m_mMemBackup.end(); it++)
		{
			TXN_ASSERT(it->second);

			DWORD* current = (DWORD*)it->first;
			DWORD* delta = (DWORD*)it->second;
			DWORD* previous = (DWORD*)it->first;

			for (size_t i = 0; i < nPageSize / sizeof(DWORD); ++i)
			{
				previous[i] = current[i] ^ delta[i];
			}
		}
	}

	return TRUE;
}

// Redo the transaction
BOOL Txn::Redo()
{
	if(m_bStarted)
		return FALSE;

	// Get memory manager
	HeapMgr* pHeapMgr = HeapMgr::Get();

	// Get page size
	size_t nPageSize = pHeapMgr->GetPageSize();

	// Restore each page
	if(m_mMemBackup.size() > 0)
	{
		std::map<void*, void*>::iterator it;
		for(it = m_mMemBackup.begin(); it != m_mMemBackup.end(); it++)
		{
			TXN_ASSERT(it->second);

			DWORD* current = (DWORD*)it->first;
			DWORD* delta = (DWORD*)it->second;
			DWORD* next = (DWORD*)it->first;

			for (size_t i = 0; i < nPageSize / sizeof(DWORD); ++i)
			{
				next[i] = current[i] ^ delta[i];
			}
		}
	}
	return TRUE;
}

// Add / Set one item into m_mMemBackup
BOOL Txn::SetMap(void* pPageStorage, void* pBackup)
{
	m_mMemBackup[pPageStorage] = pBackup;
	return TRUE;
}

